%% -*- coding: utf-8 -*-

%% @doc templerl のテスト
%%
-module(t_templ).
-import(templ, [init/0,init/1,process/1,process/2,process/3,process/4]).

-include_lib("eunit/include/eunit.hrl").

process_test_() ->
	init(),

	[?_assertMatch("123", 
				   process("123")),
	 ?_assertMatch("hoge123", 
				   process("hoge\{123\}")),
	 ?_assertMatch("123hoge", 
				   process("\{123\}hoge")),
	 ?_assertMatch("hoge123hoge", 
				   process("hoge{123}hoge")),
	 ?_assertMatch("}", 
				   process("}")),
	 ?_assertThrow({{templ,einval},{999,templ_parser,["syntax error before: ",[]]}},
				   process("{"))
	].

process1_test_() ->
	init([{"greetings",[{"en","Welcome! Hello {user.en}"}, 
						{"ja","こんにちは、{user.ja}"}]}, 
		  {"user",[{"en","{title[1]} Joe"}, {"ja","山田太郎 {title[2]}"}]},
		  {"title",["Mr.", "様"]}]),

	[?_assertMatch("Welcome! Hello Mr. Joe!",
				   process(process(process("{greetings.en}!")))),
	 ?_assertMatch("こんにちは、山田太郎 様！",
				   process(process(process("{greetings.ja}！"))))
	].

process2_test_() ->
	init([{<<"greetings">>,[{<<"en">>,<<"Welcome! Hello {user.en}">>}, 
							{<<"ja">>,<<"こんにちは、{user.ja}">>}]}, 
		  {<<"user">>,[{<<"en">>,<<"{title[1]} Joe">>}, 
					   {<<"ja">>,<<"山田太郎 {title[2]}">>}]},
		  {<<"title">>,[<<"Mr.">>, <<"様">>]}]),

	[?_assertMatch("Welcome! Hello Mr. Joe!",
				   process(process(process(<<"{greetings.en}!">>)))),
	 ?_assertMatch("こんにちは、山田太郎 様！",
				   process(process(process(<<"{greetings.ja}！">>)))),
	 ?_assertMatch("Hello Joe!",
				   process(<<"{if user.en==\"{title[1]} Joe\"}Hello Joe!{endif}">>))
	].

process_with_ctx_test_() ->
	[
	 ?_assertMatch("string", 
				   process("\{string.module\}", 
						   [{"string",[{"module",string}, {"substr",substr}]}])),
	 ?_assertMatch("string", 
				   process("\{string.module\}")),
	 ?_assertMatch("ge", 
	 		   process("\{string.module:string.substr (\"hoge\", 3)\}")),

	 ?_assertMatch("hello joe", 
				   process(process("{greetings}", [{"greetings", "hello {name}"}]), [{"name", "joe"}])),
	 ?_assertThrow({{templ_am,einval},{novalue,"module"}}, 
				   process("\{module\}"))
	].

process_with_delim_test_() ->
	[
	 ?_assertMatch("hogehoge", 
				   process("hoge{{hoge}}", [{"hoge",hoge}], "{{", "}}")),
	 ?_assertMatch("falsehoge", 
				   process("===hoge==hoge===hoge", [{"hoge",hoge}], "===", "==="))
	].


process_if_test_() ->
	init(),

	[
	 ?_assertMatch("hogefoo", 
				   process("hoge{if true}foo{endif}")),
	 ?_assertMatch("hoge", 
				   process("hoge{if (false)}foo{end}")),
	 ?_assertMatch("hogefoo", 
				   process("hoge{if true}foo{else}bar{endif}")),
	 ?_assertMatch("hogebar", 
				   process("hoge{if false}foo{else}bar{endif}")),
	 ?_assertMatch("hogefooasdf", 
				   process("hoge{if true}foo{if true}asdf{end}{else}bar{endif}")),
	 ?_assertMatch("hoge123", 
				   process("hoge{if true}{123}{endif}")),
	 ?_assertMatch("hogezero123four", 
				   process("hoge{if true}zero{123}four{endif}", [])),

	 % 真偽値変換
	 % any number is true except for 0
	 ?_assertMatch("foo", 
				   process("{if 1}foo{endif}{if 0}bar{endif}")),
	 ?_assertMatch("foo", 
				   process("{if -1}foo{endif}")),
	 ?_assertMatch("foo", 
				   process("{if 100}foo{endif}")),
	 ?_assertMatch("hoge", 
				   process("{if foo}hoge{endif}", [{"foo", 1}])),
	 ?_assertMatch("hoge", 
				   process("{if foo}hoge{endif}", [{"foo", 2}])),
	 ?_assertMatch("", 
				   process("{if 10-10}foo{endif}{if 0}bar{endif}")),
	 % any string is true except for "false", "" and "0"
	 ?_assertMatch("foobar", 
				   process("{if \"1\"}foo{endif}{if \"0.00\"}bar{endif}")),
	 ?_assertMatch("bar", 
				   process("{if \"\"}foo{else}bar{endif}")),
	 ?_assertMatch("foo", 
				   process("{if \"true\"}foo{endif}{if \"false\"}bar{endif}")),
	 ?_assertMatch("foo", 
				   process("{if \"100\"}foo{endif}")),
	 ?_assertMatch("hoge", 
				   process("{if foo}hoge{endif}", [{"foo", 1}])),
	 ?_assertMatch("hoge", 
				   process("{if foo}hoge{endif}", [{"foo", 2}])),
	 %% any reference is true
	 ?_assertMatch("", 
				   process("{if foo}hoge{endif}", [{"foo", 0}])),
	 ?_assertMatch("", 
				   process("{if foo}hoge{endif}")),
	 % any undefined value is false
	 ?_assertMatch("", 
				   process("{if foo}hoge{endif}")),
	 ?_assertMatch("hoge", 
				   process("h{if foo}{else}{foo}{endif}o{if bar}s{else}g{endif}e", [{"foo", "ir"}]))
	].

process_let_test_() ->
	[
	 ?_assertMatch("1", 
				   process("{let a = 1}{a}{end}")),
	 ?_assertMatch("foo1", 
				   process("{let hoge = 1}foo{hoge}{endlet}")),
	 ?_assertMatch("foo1bar", 
				   process("{let a = 1}foo{a}bar{endlet}")),
	 ?_assertMatch("foobar", 
				   process("{let a = \"bar\"}foo{a}{endlet}")),

	 ?_assertMatch("", 
				   process("{let a = 1}{endlet}{if a}hoge{endif}")),

	 ?_assertThrow({{templ_am,einval},{novalue,"a"}},
				   process("{let a = \"bar\"}foo{end}{a}")),
	 %?_assertError(_, process("{let a = \"bar\"}foo{a}{end}", [{"a", 123}])),
	 ?_assertMatch("foobar", process("{let a = \"bar\"}foo{a}{end}", [{"a", 123}])),
	 ?_assertThrow({{templ_am,einval},{novalue,"bar"}}, 
				   process("{let a=bar}foo{a}{end}"))
	].

process_foreach_test_() ->
	[
	 ?_assertMatch("12345", 
				   process("{foreach a in list}{a}{end}",
						   [{"list", [1, 2, 3, 4, 5]}])),
	 ?_assertMatch("a:123, b:123, c:123", 
				   process("{foreach v1 in list1}{v1}:{foreach v2 in list2}{v2}{end}{if v1 != \"c\"}, {end}{end}",
						   [{"list1", ["a", "b", "c"]}, {"list2", [1, 2, 3]}])),

	 % スコープの上書き
	 ?_assertMatch("12345", 
				   process("{foreach a in list}{a}{end}",
						   [{"a", asdf}, {"list", [1, 2, 3, 4, 5]}])),

	 % リストのリスト
	 ?_assertMatch("12345", 
				   process("{foreach a in list}{foreach a in a}{a}{endforeach}{endforeach}",
						   [{"list", [[1, 2, 3], [4, 5]]}])),

	 % first, last
	 ?_assertMatch("(true,false), (false,false), (false,false), (false,true)", 
				   process("{foreach v in list}({v.first},{v.last}){if !v.last}, {endif}{endforeach}",
						   [{"list", [1, 2, 3, 4]}])),
	 ?_assertMatch("(true,true)", 
				   process("{foreach v in list}({v.first},{v.last}){endforeach}",
						   [{"list", [1]}])),
	 % nth
	 ?_assertMatch("(0,0), (0,1), (0,2), (1,0), (1,1), (1,2), (2,0), (2,1), (2,2)", 
				   process("{foreach v1 in l1}{foreach v2 in l2}({v1.nth},{v2.nth}){if !v2.last}, {end}{end}{if !v1.last}, {end}{end}",
						   [{"l1", ["a", "b", "c"]}, {"l2", [1, 2, 3]}])),

	 ?_assertThrow({{templel_parse_handler,einval},{"hoge",{value,"v",1}},
					"undefined property"}, 
				   process("{foreach v in list}({v.hoge},{v.last}){endforeach}",
						   [{"list", [1]}, {"hoge", "first"}])),

	 % 空リスト
	 ?_assertMatch("asdf", 
				   process("as{foreach v in list}{v}{endforeach}df",
						   [{"list", []}])),
	 % 未定義
	 ?_assertMatch("", 
				   process("{foreach a in hoge}{a}{end}")),

	 % 型エラー
	 ?_assertThrow({{templ_am,einval},123}, 
				   process("{foreach v in list}{v}{endforeach}",
						   [{"list", 123}]))
	].


process_include_test_() ->
	init([{"module",erlang}, 
		  {"l2a",list_to_atom}, {"l2i",list_to_integer},
		  {"string",[{"module",string}, {"substr",substr}]},
		  {"greetings","Hello {user}"}, {"user","{title} Joe"}, {"title", "Mr."},
		  {"jgreetings","こんにちは、\{juser\} 様"}, {"juser","山田太郎"}]),

	[?_assertMatch("Welcome! Hello Mr. Joe!",
				   process(process(templ:process_file("test.tmpl")))),
	 ?_assertMatch("Welcome! Hello {user}!",
				   process("{include \"test.tmpl\"}")),
	 ?_assertMatch("Welcome! Hello Mr. Joe!",
				   process(process(process("{include \"test.tmpl\"}")))),
	 ?_assertMatch("こんにちは、{juser} 様！",
				   process("{include \"../tmp/test.tmpl\"}")),
	 ?_assertMatch("Hello {user}! Welcome! Hello {user}!! Hello {user}!!!",
				   process("{include \"../tmp/include.tmpl\"}")),
	 ?_assertMatch("Hey! Welcome! Hey!! Hey!!!",
				   process("{let greetings = \"Hey\"}{include \"../tmp/include.tmpl\"}{endlet}"))
	].
